package com.moonshineproject.plugin.haxe.haxecompiler.commands
{
	import __AS3__.vec.Vector;
	
	import com.moonshineproject.plugin.core.ExternalCommandBase;
	import com.moonshineproject.plugin.haxe.haxeproject.vo.HaXeProjectVO;
	import com.moonshineproject.text.vo.CompletionResult;
	
	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.events.Event;
	import flash.events.NativeProcessExitEvent;
	import flash.events.ProgressEvent;
	import flash.filesystem.File;
	import flash.utils.IDataInput;
	
	import mx.collections.ArrayCollection;

	public class HaxeAutoCompleteCommand extends ExternalCommandBase
	{
		override public function get name():String { return "HaXe Compiler Plugin"; }
		
		protected var project:HaXeProjectVO;
		protected var stdOutput:String = "";
		protected var stdError:String = "";
		
		public var result:ArrayCollection;
		
		
		public function HaxeAutoCompleteCommand(executable:File)
		{
			super(executable, null);
		}
		
		public function complete(p:HaXeProjectVO, args:Vector.<String>, filePath:String, charIdx:int):void
		{
			this.project = p;
			
			args.push("--display");
			args.push(filePath + "@" + charIdx)
			
			print(args.toString().replace(new RegExp(",", "g"), " "));
			
			customInfo = new NativeProcessStartupInfo();
			customInfo.executable = executable;
			
			customInfo.arguments = args;
			customInfo.workingDirectory = p.folder;

			customProcess = new NativeProcess();
			customProcess.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, haxeError);
			customProcess.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, haxeOutput);
			customProcess.addEventListener(Event.STANDARD_ERROR_CLOSE, stdErrClose);
			customProcess.addEventListener(NativeProcessExitEvent.EXIT, haxeExit);
			customProcess.start(customInfo);
		}
		
		protected function haxeError(event:ProgressEvent):void
		{
			//TODO: Parse error messages, format & output
			if (!customProcess.running) return;
			
			// Fetch output
			var output:IDataInput = (event.target as NativeProcess).standardOutput;
			if (output.bytesAvailable <= 0) return;
			stdError += output.readUTFBytes(output.bytesAvailable); 
		}
		
		protected function haxeOutput(event:ProgressEvent):void
		{
			// Fetch output
			var output:IDataInput = (event.target as NativeProcess).standardError;
			stdOutput += output.readUTFBytes(output.bytesAvailable);
		}
		
		protected function stdErrClose(event:Event):void
		{
			if (!customProcess.running) return;
			
			var output:IDataInput = (event.target as NativeProcess).standardError;
			
			if (output.bytesAvailable > 0)
				stdOutput += output.readUTFBytes(output.bytesAvailable);
		}
		
		protected function haxeExit(event:NativeProcessExitEvent):void
		{
			if (event.exitCode == 0)
			{
				XML.ignoreComments = true;
				XML.ignoreWhitespace = true;
				var data:XML = new XML(stdOutput);
				
				// TODO: Parse out other stuffs too
				var completions:Array = [];
				var c:CompletionResult;
				var label:String;
				var methodParamRegexp:RegExp = /\w+ : (\w+)/g;
				for each (var node:XML in data.i)
				{
					// Fetch name
					c = new CompletionResult();
					label = node.@n;
					c.completion = node.@n;
					
					if (node.t)
					{
						var t:String = node.t;
						var res:String = "";
						// Method
						if (t.search(/\-\>/g) > -1)
						{
							res = "(";
							
							var params:Object = methodParamRegexp.exec(t);
							while (params != null)
							{
								res += params[1] + ",";
								params = methodParamRegexp.exec(t);
							}
							// Strip that last comma if needed
							if (res.length > 1) res = res.substr(0, -1);
							
							res += ")";
							
							var ret:Array = t.match(/\w+/g);
							if (ret.length > 0)
							{
								res += ":" + ret[ret.length-1];
							}
						}
						// Assume property
						else
						{
							res = ":" + t.replace(" ", "");
						}
						
						label += res;
					}
					
					c.colors = Vector.<int>([0, 0]);
					c.label = label;
					
					completions[completions.length] = c;
				}
				
				result = new ArrayCollection(completions);
				
				// Tell 'em we're done here
				dispatchEvent(new Event(Event.COMPLETE));
			}
			else
			{
				error("Completion failed: %s", stdError);
				
				dispatchEvent(new Event(Event.CANCEL));
			}
			
			customProcess = null;
		}
		
	}
}